package rpc.netcon.jetty.client;

import java.lang.reflect.Proxy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import rpc.netcon.RpcRequest;
import rpc.netcon.RpcResponse;

/**
 * Created by zhangyanfei on 2018/10/11.
 * 客戶端的远程代理类 创建工厂
 *
 * @author zhangyanfei
 * @date 2018/10/11
 */
public class NetComClientProxy implements FactoryBean<Object> {
    private static final Logger logger = LoggerFactory.getLogger(NetComClientProxy.class);

    private Class<?> iface;
    private String serverAddress;
    private String accessToken;
    private JettyClient jettyClient;

    public NetComClientProxy(Class<?> iface, String serverAddress, String accessToken,
                             JettyClient jettyClient) {
        this.iface = iface;
        this.serverAddress = serverAddress;
        this.accessToken = accessToken;
        this.jettyClient = jettyClient;
    }

    /**
     * java 代理
     * 构建代理类 并留下方法回调
     * @return
     * @throws Exception
     */
    @Override
    public Object getObject() throws Exception {
        /**
         * 1.类加载器
         * 2.接口
         * 3.方法回调
         */
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] {iface},
            (proxy, method, args) -> {
                // filter method like "Object.toString()"
                if (Object.class.getName().equals(method.getDeclaringClass().getName())) {
                    logger.error(">>>>>>>>>>> xxl-rpc proxy class-method not support [{}.{}]",
                        method.getDeclaringClass().getName(), method.getName());
                    throw new RuntimeException("xxl-rpc proxy class-method not support");
                }
                RpcRequest request = new RpcRequest();
                request.setServerAddress(serverAddress);
                request.setCreateMillisTime(System.currentTimeMillis());
                request.setAccessToken(accessToken);
                request.setClassName(method.getDeclaringClass().getName());
                request.setMethodName(method.getName());
                request.setParameterTypes(method.getParameterTypes());
                request.setParameters(args);
                RpcResponse response = jettyClient.send(request);
                // valid response
                if (response == null) {
                    throw new Exception("Network request fail, response not found.");
                }
                if (response.isError()) {
                    throw new RuntimeException(response.getError());
                } else {
                    return response.getResult();
                }
            });
    }

    @Override
    public Class<?> getObjectType() {
        return iface;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
